#include <stdio.h>
#include <thread>
#include <functional>

#include "sdp.hpp"
#include "tcp.hpp"
#include "sys_var.hpp"
#include "leds.hpp"
#include "at.hpp"
#include "dtu.hpp"
#include "misc.h"

tcpClient::tcpClient(const std::string &server, int port) : CUVClient(server, port) {}

tcpClient ::~tcpClient() {}

void tcpClient ::OnRecv(const char *data, size_t s, CUVClient::err_code e)
{
	if (e == CUVClient::OK){
		if (cb_recv)
			cb_recv(s, data);
	}else{ // 接收数据发生错误，这时s是libuv返回的错误代码
		if (cb_error){
			cb_error(e);
		}
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
tcp::tcp(io_type type, filterList *l) : filterIO(type, l),
	m_short_keep_timer([this] {  
		if( m_is_short_link == true ){ close(); } 
	}, 1000, true)
{
	p_tcp = nullptr;
	m_is_short_link = false;
	m_heart_en = false;
	m_is_connecting = false;
	m_reg_en = false;
	m_conn_timer( 3000 );
	m_conn_timer.SetOwner([this] {
		if (IsConnected() == false){reconnect();}else{
			m_conn_timer.Stop();
		}
	});
	std::shared_ptr<CSysVar> ptvar = GetOrCreateSysVar();
	bool sdp_en = false;
	if (ptvar){
		ptvar->GetValue("/net/sdpen", sdp_en);
		m_sdp_en = sdp_en;
	}
}

tcp::tcp(const std::string &server, int port, io_type type, filterList *l) 
: filterIO(type, l),
  p_tcp(new tcpClient(server, port)),
  m_short_keep_timer([this] { if( m_is_short_link == true ){ close(); } }, 1000, true)
{
	m_heart_en = false;
	m_reg_en = false;
	m_is_connecting = false;
	
	m_conn_timer( 3000 );

	m_conn_timer.SetOwner([this] {
		__show_line_2();
		if (IsConnected() == false){
			__show_line_1("%s%s%s", TYELLOW, "m_conn_timer triggered. try reconnect", TNORMAL);
			reconnect();
		}else{
			__show_line_1("%s%s%s", TYELLOW, "m_conn_timer triggered. stop the timer.", TNORMAL);
			m_conn_timer.Stop();
		}
	});

	std::shared_ptr<CSysVar> ptvar = GetOrCreateSysVar();
	bool sdp_en = false;

	if (ptvar){
		ptvar->GetValue("/net/sdpen", sdp_en);
		m_sdp_en = sdp_en;
	}
	connect();
}

tcp::~tcp()
{
	m_heart_timer.Stop();
}

void tcp::init_heart()
{
	std::shared_ptr<CSysVar> ptvar = GetOrCreateSysVar();

	if (ptvar){
		bool en;
		long intval;
		std::stringstream ss;
		std::string str;

		ss << m_index.load();
		str = "/net/socket/sock" + ss.str() + "/heart/";
		ptvar->GetValue(str + "enable", en);
		m_heart_en = en;
		ptvar->GetValue(str + "heart_send_intval", intval );
		m_heart_intval = intval;
		ptvar->GetValue( str + "data", m_heart_data );
		ptvar->GetValue( str + "hex" , en );
		m_heart_hex = en;
		if( m_heart_hex == true ){// 将数据转换为16禁止串
			init_heart_hex();
		}
		m_heart_timer(intval * 1000);
		m_heart_timer.SetOwner([this] {
			if (!IsInSerialAT()){
				std::stringstream ss;
				ss << "socket ID = [ " << TGREEN << m_index.load() << " ]" << TNORMAL << " heart timer called.";
				__show_line( ss.str() );
				if( m_heart_hex == true ){
					p_tcp->Send( ( char *)m_heart_data_hex.data() , m_heart_data_hex.size() );
				}else{
					p_tcp->Send(m_heart_data.c_str(), m_heart_data.length());
				}
			}

			m_heart_timer.Start(-1, true);
		});

		if (m_heart_en == true && m_is_short_link == false)
			m_heart_timer.Start(-1, true);
	}
	else{
		std::cout << "Can not initialize heart package for sysvar fail." << std::endl;
		abort();
	}
}

void tcp::init_reg()
{
	std::shared_ptr<CSysVar> ptvar = GetOrCreateSysVar();

	if (ptvar){
		bool en;
		std::string type, send_type;
		std::stringstream ss;
		std::string str;
		ss << m_index.load();
		str = "/net/socket/sock" + ss.str() + "/reg/";

		ptvar->GetValue(str + "enable", en);
		m_reg_en = en;
		ptvar->GetValue(str + "data_type", type);
		ptvar->GetValue(str + "type", send_type);
		// 16禁止注册包
		ptvar->GetValue( str + "hex" , en );
		m_reg_hex = en;

		m_reg_send_type = std::move(send_type);
		if (type == "USER"){
			ptvar->GetValue( str + "data", m_reg_data );
			if( m_reg_hex == true ){// 将数据转换为16禁止串
				init_reg_hex();
			}
		}
		else if (type == "ICCID" ){
			m_reg_data = ec20dial::GetICCID();
		}
		else if (type == "IMEI"){
			m_reg_data = ec20dial::GetIMEI();
		}
		else if (type == "CLOUD"){
			// TODO , 添加和SignalCloud 互动的代码
		}
		else{
			m_reg_data = ec20dial::GetIMEI();
		}
	}else{
		std::cout << "Can not initialize register package for sysvar fail." << std::endl;
		abort();
	}
}

void tcp::init_heart_hex()
{
	uint8_t * hex_data = ( uint8_t *)malloc( m_heart_data.length() );
	if( hex_data ){
		try{
			size_t len = str2hex( m_heart_data , hex_data );
		
			if( len > 0 ){
				try{
					m_heart_data_hex.data( hex_data , len );
					free( hex_data );
				}catch( ... ){
					__show_line_1("%s%s%s" , TRED , "Convert heart packet data fail." , TNORMAL);
				}
			}
		}catch( BufferByte::err_code e ){
			__show_line_1( "%s%s%s" , TRED , "Convert heart packet data fail." , TNORMAL );
		}
	}else{
		__show_line_1( "%s%s%s" , TRED , "Allocate memory fail." , TNORMAL );
	}
}

void tcp::init_reg_hex()
{
	uint8_t * hex_data = ( uint8_t *)malloc( m_reg_data.length() );
	if( hex_data ){
		try{
			size_t len = str2hex( m_reg_data , hex_data );
			if( len > 0 )
				m_reg_data_hex.data( hex_data , len );

			free( hex_data );
		}catch( BufferByte::err_code e ){
			__show_line_1( "%s%s%s" , TRED , "Convert register packet data fail." , TNORMAL );
		}
	}else{
		__show_line_1( "%s%s%s" , TRED , "Allocate memory fail." , TNORMAL );
	}
}

void tcp :: __init_short_link( std::shared_ptr< CSysVar>& ptvar )
{
	std::stringstream ss;
	ss << "/net/socket/sock" << m_index.load() ;
	std::string str = ss.str() + "/shortReconn";
	int data = -1;
	
	ptvar->GetValue( str , data );
	if( data > 0 ){
		data = data * 1000;
		__show_line_1( "%s%s data = %s%d%s" , TYELLOW , __PRETTY_FUNCTION__ , TBLUE , data , TNORMAL );
		m_short_keep_intval = data;
	}
}

void tcp :: __init_long_link(  std::shared_ptr< CSysVar >& ptvar )
{
	std::stringstream ss;
	std::string str;
	int data = -1;

	ss << "/net/socket/sock" << m_index.load() ;
	str = ss.str() + "/reconnectTime";			// 重连时间
	ptvar->GetValue( str, data);
	if (data > 0){
		data = data * 1000;
		m_conn_timer(data);
	}
}

void tcp::Index(int i)
{
	m_index = i;
	m_is_connecting = false;
	std::shared_ptr<CSysVar> ptvar = GetOrCreateSysVar();
	if (ptvar){
		std::stringstream ss;
		ss << "/net/socket/sock" << i ;
		std::string str;

		str = ss.str() + "/link";
		ptvar->GetValue( str , str );
		if( str == "SHORT" ){
			__show_line_2();
			m_is_short_link = true;
			__init_short_link( ptvar );
		}else if( str == "LONG" ){
			__show_line_2();
			m_is_short_link = false;
			__init_long_link( ptvar );
		}else{
			// 错误的连接类型
		}
	}
	init_heart();
	init_reg();
}

tcp::err_code tcp::connect()
{
	if(m_is_connecting == true ) return OK;
	if( !p_tcp )
		p_tcp = std::move(std::unique_ptr<tcpClient>(new tcpClient(m_svr, m_port)));
	
	if (p_tcp){
		on_open([this] {
			m_is_connecting = false;
			if( m_is_short_link == false )
				StopRebootTimer();
			if( m_is_short_link == false )
				m_conn_timer.Stop();
			// 判断当前连接的通道，如果通道在1，2则点亮对应的LED
			if (m_index == 1)
				led::GetLed()->socka(true);
			else if (m_index == 2)	{
				led::GetLed()->sockb(true);
			}
			// 如果是短连接则设置超时操作计时器。
			if (m_is_short_link == true){
				__show_line_2();
				m_short_keep_timer.Start(m_short_keep_intval, true);
			}

			if (m_reg_en == true){ // 如果用户开启了注册包，则按照要求发送注册包
				if (m_reg_send_type == "LINK" || m_reg_send_type == "BOTH")	{
					sleep(1);
					if( m_reg_hex == true )
						p_tcp->Send( ( char *)m_reg_data_hex.data(), m_reg_data_hex.size() );
					else
						p_tcp->Send(m_reg_data.c_str(), m_reg_data.length());
				}
			}
		});
		on_close([this] {
			// 判断当前连接的通道，如果通道在1，2则关闭对应的LED
			if (m_index == 1)
				led::GetLed()->socka(false);
			else if (m_index == 2){
				led::GetLed()->sockb(false);
			}
			// 如果是短连接则设置超时操作计时器。
			if (m_is_short_link == true){
				m_short_keep_timer.Stop();
			}

			if (m_heart_timer.IsRuning()){
				m_heart_timer.Stop();
			}
			if( m_is_short_link == false )
				StartRebootTimer();
		});
		on_data([this](size_t len, const char *data) {
			OnRecv(len, data, OK);
		});

		on_send([this](size_t s) {
			__show_line_1("%s%s%d%s%s", TYELLOW, "TCP SENDED [ ", m_index.load(), " ]", TNORMAL);
		});

		on_error([this](CUVClient::err_code e) {
			m_is_connecting = false;
			
			if( m_is_short_link == false )
				m_conn_timer.Start(-1, true);

			if (m_index == 1)
				led::GetLed()->socka(false);
			else if (m_index == 2)	{
				led::GetLed()->sockb(false);
			}
			StartRebootTimer();
		});

		p_tcp->connect();
		if( m_is_short_link == false )
			m_conn_timer.Start(-1, true);
	}

	return m_error.load();
}

tcp::err_code
tcp::connect(const std::string &server, int port)
{
	if( m_is_connecting == true ) return OK;
	m_is_connecting = true;
	if( !p_tcp ){
		p_tcp = std::move(std::unique_ptr<tcpClient>(new tcpClient(server, port)));
	}
	if (p_tcp){
		m_svr = server;
		m_port = port;

		on_data([this](size_t len, const char *data) {
			OnRecv(len, data, OK);
		});

		on_open([this] {
			m_conn_timer.Stop();
			if( m_is_short_link == false )
				StopRebootTimer();
			// 判断当前连接的通道，如果通道在1，2则点亮对应的LED
			if (m_index == 1)
				led::GetLed()->socka(true);
			else if (m_index == 2){
				led::GetLed()->sockb(true);
			}
			usleep( 100000 );
			if (m_reg_en == true){
				if (m_reg_send_type == "LINK" || m_reg_send_type == "BOTH")	{
					if( m_reg_hex == true )
						p_tcp->Send(( char *)m_reg_data_hex.data(), m_reg_data_hex.size() );
					else
						p_tcp->Send(m_reg_data.c_str(), m_reg_data.length());
				}
			}
			if( m_is_short_link == true ){
				m_short_keep_timer.Start(m_short_keep_intval.load(), true);
				m_mutex.lock();
				if( m_short_buff.size() > 0 ){  // 短连接缓冲区存在数据
					__show_line_1( "%s%s%s" , TYELLOW , __PRETTY_FUNCTION__ , TNORMAL );
					for( auto it = m_short_buff.begin(); it != m_short_buff.end(); it ++ ){
						char * data = (*it).data();
						size_t len = (*it).size();
						if( data == nullptr || len == 0 ) continue;

						if (m_sdp_en == true)
						{ // 如果开启SDP，则判断是否是满足SDP要求的数据，如果是则发送
							__show_line_1("%s%s%s", TBLUE, "TCP-SDP-ON.", TNORMAL);
							forward_sdp(len, data);
						}else{
							forward_normal(len, data);
						}// else m_sd_en == true
					}// for( auto it = m_short_buff.begin)

					m_short_buff.erase( m_short_buff.begin() , m_short_buff.end() );
				}// if( m_short_buff.size() > 0 )
				m_mutex.unlock();
			}// if(m_is_short_link == true )

			m_is_connecting = false;
		});

		on_close([this] {
			// 判断当前连接的通道，如果通道在1，2则关闭对应的LED
			if (m_index == 1){
				led::GetLed()->socka(false);
			}
			else if (m_index == 2){
				led::GetLed()->sockb(false);
			}

			// 如果是短连接则设置超时操作计时器。
			if (m_is_short_link == true){
				m_short_keep_timer.Stop();
			}
			if( m_is_short_link == false )
				StartRebootTimer();
		});

		on_send([this](size_t len) {
			__show_line_1("%s%s%d%s" , TGREEN , "[NET SENDED] AT SOCKET " , m_index.load() , TNORMAL );
		});

		on_error([this](CUVClient::err_code e) {
			__show_line_2();
			m_is_connecting = false;
			if( m_is_short_link == false ){
				m_conn_timer.Start(-1, true);
				StartRebootTimer();
			}

			if (m_index == 1) led::GetLed()->socka(false);
			else if (m_index == 2){ led::GetLed()->sockb(false);}
		});

		p_tcp->connect(server, port);
		if( m_is_short_link == false ) m_conn_timer.Start(-1, true);
	}

	return m_error.load();
}

void tcp::close()
{
	if (p_tcp)
		p_tcp->Close();
}

bool tcp::forward_sdp(size_t len, const char *data)
{
	sdp __sdp;
	bool ret = false;
	void *__data = nullptr;
	size_t __len = 0;
	
	if (__sdp.Unpack(data, len)){
		__show_line_1("%s%s%s", TBLUE, "TCP-SDP-ON.", TNORMAL);
		int socket = __sdp.socket();
		__show_line_1("\n%s socket = %ld %s\n", TRED, socket, TNORMAL);
		if (socket == m_index.load())
		{
			__show_line_1("%s%s%d%s" , TYELLOW , "SDP send : " , m_index.load() , TNORMAL );

			__len = __sdp.GetData(&__data);
			if (m_reg_send_type == "DATA" || m_reg_send_type == "BOTH"){ // 发送注册包
				if( m_reg_hex ){
					p_tcp->Send( (char *)m_reg_data_hex.data(), m_reg_data_hex.size());
				}else{
					p_tcp->Send(m_reg_data.c_str(), m_reg_data.length());
				}
			}
			if (__data)
				p_tcp->Send((const char *)__data, __len);
		}
	}
	if (__data)
		free(__data);

	return ret;
}


bool tcp::forward_short(size_t len, const char *data)
{
	bool ret = false;
	if (m_heart_en == true)	{
		m_heart_en = false;
		m_heart_timer.Stop();
	}

	if (IsConnected() == false)	{ // 如果目前没有链接服务器，则尝试链接服务器

		__add_to_pending_buff( data , len );

		std::thread thd([this] { reconnect(); });
		thd.detach();
	}else{ // 如果目前已经链接，则直接发送数据
		m_short_keep_timer.Reset();

		if (m_sdp_en == true){ // 如果开启SDP，则判断是否是满足SDP要求的数据，如果是则发送
			forward_sdp(len, data);
		}else{
			forward_normal(len, data);
		}
	}
	return ret;
}

bool tcp::forward_normal(size_t len, const char *data)
{
	if (m_reg_send_type == "DATA" || m_reg_send_type == "BOTH" ){// 发送前在数据前添加注册包
		if( m_reg_hex ){
			p_tcp->Send(( char *)m_reg_data_hex.data(), m_reg_data_hex.size());
		}
		else{
			p_tcp->Send(m_reg_data.c_str(), m_reg_data.length());
		}
	}
	p_tcp->Send(data, len);

	return true;
}
//串口数据到网络
bool tcp::on_forward(size_t len, const char *data, err_code &err, size_t &rlen, char **rd)
{
	CUVClient::err_code e = (CUVClient::err_code)0;

	if (m_heart_en == true)	{ // 如果心跳包启动，则复位心跳包计时器
		m_heart_timer.Reset();
	}
	std::string str(data);
	str = str.substr( 0 , len );
	__show_line( str );
	if (IsInSerialAT() || str.find("#AT") != std::string::npos)	{
		*rd = (char *)data;
		rlen = len;
		return false;
	}

	if (len == 3){
		if ( str == "+++" )	{
			*rd = (char *)data;
			rlen = len;
			return false;
		}
	}
	if(p_tcp){
		if (m_is_short_link == true){
			forward_short(len, data);
		}else if( *(p_tcp.get()) ){  // 如果tcp没有建立连接则放弃发送
			if (m_sdp_en == true)
			{ // 如果开启SDP，则判断是否是满足SDP要求的数据，如果是则发送				
				forward_sdp(len, data);
			}else{
				__show_line_1("%s%s%s", TBLUE, "TCP-SDP-OFF.", TNORMAL);
				forward_normal(len, data);
			}
		}else{
			rlen = 0;
			*rd = nullptr;
			return false;
		}
	}
	if (e == CUVClient::OK)	{
		rlen = len;
		*rd = (char *)data;
	}
	return false;
}
//网络数据到串口  data是原始数据，rd 带回的打包后的数据
bool tcp::on_backward(size_t len, const char *data, err_code &err, size_t &rlen, char **rd)
{
	if (m_heart_en == true)	{
		m_heart_timer.Reset();
	}
	if (data == nullptr || len == 0)
		return false;
	if (IsInSerialAT())	{
		*rd = (char *)data;
		rlen = len;
		return false;
	}
	if (m_sdp_en == false){ // 如果没有启动SDP，则直接返回数据
		rlen = len;
		*rd = (char *)data;
	}else{ // 如果启动SDP，则将网络来的数据打包成串口结构数据
		sdp __sdp;
		__show_line_1("%s%s%s", TBLUE, "TCP-COM-ON.", TNORMAL);
		__sdp.Net((sdp::net)(m_index.load() + 0x60), data, len);
		void *__data = nullptr;
		rlen = __sdp.GetPackRaw(&__data);
		*rd = (char *)__data;
	}
	return true;
}

void tcp :: __add_to_pending_buff( const char * data , size_t s )
{
	if( data == nullptr || s == 0 ) return;
	try{  
		stPendingBuff buff( s , data );
		m_mutex.lock();
		m_short_buff.push_back( buff );
		m_mutex.unlock();
	}catch( char * d ){
		__show_line("Allocate memory fail.");
		abort();
	}
}